#include "tracimportprojectselectwidget.h"
#include "ui_tracimportprojectselectwidget.h"
#include "tracsettings.h"

#include "xmlrpcbase64.h"
#include "xmlrpcconnection.h"
#include "xmlrpcparser.h"
#include "xmlrpcrequest.h"
#include "xmlrpcresponse.h"

#include "informationwidget.h"

#include <QtCore/QDebug>
#include <QtCore/QUrl>
#include <QtXml/QDomDocument>
#include <QtGui/QMessageBox>

using XmlRpc::XmlRpcConnection;
using XmlRpc::XmlRpcRequest;
using XmlRpc::XmlRpcResponse;
using XmlRpc::XmlRpcBase64;

namespace Trac {
namespace Internal {

TracImportProjectSelectWidget::TracImportProjectSelectWidget(QWidget *parent) :
    QWidget(parent),
    m_valid(false),
    m_connection(new XmlRpcConnection(this)),
    m_response(0),
    m_infoWidget(0)
{
    ui = new Ui::TracImportProjectSelectWidget();
    ui->setupUi(this);
    setMinimumWidth(500);

    m_infoWidget = new InformationWidget(this);
    ui->gridLayout->addWidget(m_infoWidget, 0, 0, 1, ui->gridLayout->columnCount());

    connect(ui->nameFilterEdit, SIGNAL(textEdited(QString)),
            this, SLOT(searchProjects()));
    connect(ui->categoriesTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*, int)),
            this, SLOT(selectCategories(QTreeWidgetItem*)));
    connect(ui->projectsTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*, int)),
            this, SLOT(projectClicked(QTreeWidgetItem*)));
    connect(m_connection, SIGNAL(finished(XmlRpc::XmlRpcResponse*)),
            this, SLOT(rpcQueryCompleted(XmlRpc::XmlRpcResponse*)));
}

TracImportProjectSelectWidget::~TracImportProjectSelectWidget()
{
    delete ui;
}

bool TracImportProjectSelectWidget::isValid() const
{
    return m_valid;
}


const QString TracImportProjectSelectWidget::connectionUrl()
{
    return m_connection->url().toString();
}

void TracImportProjectSelectWidget::setConnectionUrl(const QString &url)
{
    m_connection->setUrl(QUrl(url));

}

void TracImportProjectSelectWidget::initialize()
{
    m_connection->setUrl(QUrl(TracSettings::instance()->hostName()));
    m_connection->setUsername(TracSettings::instance()->username());
    m_connection->setPassword(TracSettings::instance()->password());

    m_projectData.clear();

    ui->nameFilterEdit->clear();

    ui->nameFilterEdit->setEnabled(false);
    ui->categoriesTreeWidget->clear();
    ui->projectsTreeWidget->clear();
    ui->labelCurrentProject->clear();
}

void TracImportProjectSelectWidget::requestProjectCategories()
{
    m_request.setMethod(Constants::RPC_GETPROJECTCATEGORIES);
    m_request.setParams(QVariantList());
    m_connection->query(m_request);
}


void TracImportProjectSelectWidget::rpcQueryCompleted(XmlRpc::XmlRpcResponse *response)
{
    if (response->error()) {
        QString errorString;
        if (response->errorCode() == 401)
                errorString = tr("Authentication failed.\nPlease enter correct user credentials "
                             " or select anonymous login.");
            else
                errorString = response->errorString();
        m_infoWidget->display(QString(tr("ERROR (%1): %2")).arg(response->errorCode())
                              .arg(errorString), "", 0, 0);
        m_valid = false;
        emit validChanged(m_valid);
    }  else {
        ui->nameFilterEdit->setEnabled(true);

        QVariantList values = response->returnValue().toList();

        if (response->methodCalled() == Constants::RPC_GETPROJECTCATEGORIES && values.count() > 0) {
            populateCategories(values);
            searchProjects();
        } else if (response->methodCalled() == Constants::RPC_SEARCHPROJECTS && values.count() > 0
                 && m_response == response) {
            populateProjects(values);
        }
    }
    response->deleteLater();
}

void TracImportProjectSelectWidget::populateCategories(const QVariantList list)
{
    if(!list.empty()) {
        QTreeWidgetItem *topItem = new QTreeWidgetItem();
        topItem->setText(0, "All categories");
        ui->categoriesTreeWidget->addTopLevelItem(topItem);
        ui->categoriesTreeWidget->setItemSelected(topItem, true);
        parseCategories(list);
    }
}

void TracImportProjectSelectWidget::parseCategories(const QVariantList list, QTreeWidgetItem *parentItem)
{
    //TODO: Should work with n amount of sub categories but might be a good idea to rethink this


    QVariantList varList;
    QTreeWidgetItem *lastItem;

    for(int i = 0; i < list.count(); i++) {
        if(QString(list.value(i).typeName()) != "QVariantList") {
            if(parentItem == 0) {
                lastItem = new QTreeWidgetItem();
                lastItem->setText(0, list.value(i).toString());
                ui->categoriesTreeWidget->addTopLevelItem(lastItem);
            }
            else {
                lastItem = new QTreeWidgetItem();
                lastItem->setText(0, list.value(i).toString());
                parentItem->addChild(lastItem);
            }

        }
        else {
            varList = list.value(i).toList();
            parseCategories(varList, lastItem);

        }
    }
}


void TracImportProjectSelectWidget::populateProjects(QVariantList values)
{
    ProjectData projectData;
    QStringList tmp;

    for (int i = 0; i < values.count(); i++) {
        tmp = values.value(i).toString().split("|");
        if (tmp.count() != 2)
            continue;
        projectData.identifier = tmp.at(0);
        projectData.name = tmp.at(1);
        m_projectData.insert(i, projectData);

        QTreeWidgetItem *projectName = new QTreeWidgetItem();
        projectName->setText(0, projectData.name);
        ui->projectsTreeWidget->addTopLevelItem(projectName);
    }

}


void TracImportProjectSelectWidget::selectCategories(QTreeWidgetItem *selectedCategory)
{
    if(selectedCategory == ui->categoriesTreeWidget->topLevelItem(0)) {
        ui->categoriesTreeWidget->clearSelection();
        ui->categoriesTreeWidget->setItemSelected(ui->categoriesTreeWidget->topLevelItem(0), true);
    }
    else {

        int childCount = selectedCategory->childCount();

        selectedCategory->setExpanded(true);

        for(int i = 0; i < childCount; i++) {
            selectedCategory->child(i)->setSelected(selectedCategory->isSelected());
        }


        if(ui->categoriesTreeWidget->selectedItems().count() == 0)
            ui->categoriesTreeWidget->setItemSelected(ui->categoriesTreeWidget->topLevelItem(0), true);
        else
            ui->categoriesTreeWidget->setItemSelected(ui->categoriesTreeWidget->topLevelItem(0), false);
    }

    searchProjects();
}

void TracImportProjectSelectWidget::searchProjects()
{
    QVariantList parameters;
    QStringList categoryList;

    if (ui->categoriesTreeWidget->selectedItems().at(0)->text(0) != "All categories")
        foreach (QTreeWidgetItem* category, ui->categoriesTreeWidget->selectedItems()) {
            categoryList.append(category->text(0));
        }

    parameters << ui->nameFilterEdit->text() << categoryList;

    ui->projectsTreeWidget->clear();
    m_request.setMethod(Constants::RPC_SEARCHPROJECTS);
    m_request.setParams(parameters);
    m_response = m_connection->query(m_request);
}

void TracImportProjectSelectWidget::projectClicked(QTreeWidgetItem *selectedItem)
{
    if (selectedItem != 0) {
        ProjectData data =
                m_projectData.value(selectedItem->treeWidget()->indexOfTopLevelItem(selectedItem));
        ui->labelCurrentProject->setText(data.name);
        TracSettings::instance()->setCheckoutDirectory(data.identifier);
    }
    m_valid = selectedItem != 0;
    emit validChanged(m_valid);
}

} // namespace Internal
} // namespace Trac
